home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
Other Langs
/
MacPerl ƒ
/
Perl Source ƒ
/
Perl
/
SubLaunch.c
< prev
next >
Wrap
Text File
|
1993-12-20
|
9KB
|
376 lines
/*********************************************************************
Project : SubLaunch - Call ToolServer
File : SubLaunch.c - The code
Author : Matthias Neeracher
Started : 06Dec91 Language : MPW C/C++
Modified : 06Dec91 MN
07Mar92 MN
25Nov93 MN Mo' better spin
Last : 25Nov93
Copyright (c) 1991, 1992 Matthias Neeracher
You may distribute under the terms of the Perl Artistic License,
as specified in the README file.
*********************************************************************/
/* We need glue for Gestalt, but not for the rest of the stuff */
#include <GestaltEqu.h>
#include "SubLaunch.h"
#include <TFileSpec.h>
#include <GUSI.h>
#include <Processes.h>
#include <AppleEvents.h>
#include <CursorCtl.h>
#include <Resources.h>
#include <QuickDraw.h>
#include <Folders.h>
#include <Errors.h>
#include <Script.h>
#include <string.h>
#define FAILOSERR(call) if (err = call) return err
#define ToolServer 'MPSX'
/* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
static OSErr ToolServerRunning(ProcessSerialNumber *psn)
{
OSErr err;
ProcessInfoRec info;
psn->highLongOfPSN = 0;
psn->lowLongOfPSN = kNoProcess;
do {
FAILOSERR(GetNextProcess(psn));
info.processInfoLength = sizeof(info);
info.processName = nil;
info.processAppSpec = nil;
FAILOSERR(GetProcessInformation(psn,&info));
} while(info.processSignature != ToolServer);
*psn = info.processNumber;
return noErr;
}
static OSErr GetSysVolume(short *vRefNum)
{
long dir;
return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
}
static OSErr GetIndVolume(short index, short *vRefNum)
{
OSErr err;
ParamBlockRec pb;
pb.volumeParam.ioNamePtr = nil;
pb.volumeParam.ioVolIndex = index;
FAILOSERR(PBGetVInfoSync(&pb));
*vRefNum = pb.volumeParam.ioVRefNum;
return noErr;
}
static OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
{
OSErr err;
HParamBlockRec pb;
GetVolParmsInfoBuffer info;
pb.ioParam.ioNamePtr = nil;
pb.ioParam.ioVRefNum = vRefNum;
pb.ioParam.ioBuffer = (Ptr)&info;
pb.ioParam.ioReqCount = sizeof(GetVolParmsInfoBuffer);
FAILOSERR(PBHGetVolParmsSync(&pb));
*hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
return noErr;
}
static OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
{
OSErr err;
DTPBRec pb;
/* Get Acess path to Desktop database on this volume */
pb.ioVRefNum = vRefNum;
pb.ioNamePtr = nil;
FAILOSERR(PBDTGetPath(&pb));
pb.ioIndex = 0;
pb.ioFileCreator = ToolServer;
pb.ioNamePtr = file->name;
switch (err = PBDTGetAPPLSync(&pb)) {
case noErr:
file->vRefNum = vRefNum;
file->parID = pb.ioAPPLParID;
return noErr;
case fnfErr:
return afpItemNotFound; /* Bug in PBDTGetAPPL */
default:
return err;
}
}
/* LaunchApplication in 32 bit everything environment */
pascal OSErr WrappedLaunchApplication(const LaunchParamBlockRec *LaunchParams);
static OSErr LaunchIt(const FSSpecPtr fileSpec, ProcessSerialNumber *psn )
{
OSErr err;
LaunchParamBlockRec pb;
pb.launchBlockID = extendedBlock;
pb.launchEPBLength = extendedBlockLen;
pb.launchFileFlags = launchNoFileFlags;
pb.launchControlFlags = launchContinue | launchNoFileFlags | launchDontSwitch;
pb.launchAppSpec = fileSpec;
pb.launchAppParameters = nil;
FAILOSERR(WrappedLaunchApplication(&pb));
*psn = pb.launchProcessSN;
return noErr;
}
/* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
static OSErr LaunchToolServer(ProcessSerialNumber *psn)
{
OSErr err;
short sysVRefNum, vRefNum, index;
FSSpec file;
Boolean hasDesktopDB;
/* See if ToolServer is already running: */
err = ToolServerRunning(psn);
if (err != procNotFound)
return err;
/* Not running, try to launch it */
FAILOSERR(GetSysVolume(&sysVRefNum));
vRefNum = sysVRefNum;
for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
if (!index || vRefNum != sysVRefNum) {
FAILOSERR(VolHasDesktopDB(vRefNum,&hasDesktopDB));
if (hasDesktopDB)
switch (err = FindAppOnVolume(vRefNum, &file)) {
case noErr:
return LaunchIt(&file,psn);
case afpItemNotFound:
break;
default:
return err;
}
}
}
switch (err) {
case nsvErr:
case afpItemNotFound:
return fnfErr;
default:
return err;
}
}
typedef enum {
dontKnow,
canRun,
cantRun
} featureCheck;
static featureCheck requiredFeatures = dontKnow;
#define HASBIT(bit) (answer&(1<<bit))
#define GESTALT(sel) !Gestalt(sel, &answer)
OSErr ValidateFeatures()
{
long answer;
switch (requiredFeatures) {
case canRun:
return noErr;
case cantRun:
return gestaltUnknownErr;
case dontKnow:
if ( GESTALT(gestaltAppleEventsAttr) &&
HASBIT(gestaltAppleEventsPresent) &&
GESTALT(gestaltFindFolderAttr) &&
HASBIT(gestaltFindFolderPresent) &&
GESTALT(gestaltOSAttr) &&
HASBIT(gestaltLaunchCanReturn) &&
HASBIT(gestaltLaunchFullFileSpec) &&
HASBIT(gestaltLaunchControl) &&
GESTALT(gestaltFSAttr) &&
HASBIT(gestaltHasFSSpecCalls)
)
requiredFeatures = canRun;
else
requiredFeatures = cantRun;
return ValidateFeatures();
}
}
#define FAILOSERR(call) if (err = call) return err
/* Create a temporary file in the temp folder.
*/
OSErr FSpMakeTempFile(FSSpec * desc)
{
static int id = 0;
OSErr err;
FAILOSERR(FindFolder(kOnSystemDisk, 'temp', true, &desc->vRefNum, &desc->parID));
*((long *) desc->name) = '\007tmp';
do {
desc->name[4] = id / 1000 % 10 + '0';
desc->name[5] = id / 100 % 10 + '0';
desc->name[6] = id / 10 % 10 + '0';
desc->name[7] = id % 10 + '0';
++id;
err = HCreate(desc->vRefNum, desc->parID, desc->name, 'TEMP', 'TEXT');
} while (err == dupFNErr);
return err;
}
pascal Boolean SubLaunchIdle(EventRecord * ev, long * sleep, RgnHandle *)
{
SpinCursor(1);
if (ev->what == kHighLevelEvent)
if (AEProcessAppleEvent(ev))
return true;
*sleep = 10;
return false;
}
static char * Fragments[] = {
"Directory \'",
"\'; Begin; ",
"; End<\'",
"\' >\'",
"\' ≥\'",
"\'\n",
"Dev:Null"
};
#define BEGIN_TEXT Fragments[0]
#define DIRSET_TEXT Fragments[1]
#define END_TEXT Fragments[2]
#define STDOUT_TEXT Fragments[3]
#define STDERR_TEXT Fragments[4]
#define TERM_TEXT Fragments[5]
#define DEVNULL_TEXT Fragments[6]
#define DEVSTRING(dev) \
if (dev) \
segment = FSp2FullPath(dev); \
else \
segment = DEVNULL_TEXT
/* Execute the command. Any of the files may be set to NULL */
OSErr SubLaunch(char * commandline, FSSpec * input, FSSpec * output, FSSpec * error)
{
OSErr err;
Boolean same;
ProcessSerialNumber psn;
ProcessSerialNumber me;
AppleEvent cmd;
AppleEvent reply;
AEAddressDesc addr;
acurHandle acur;
Handle text;
char * segment;
FSSpec vol;
/* Check if the system is sexy enough */
FAILOSERR(ValidateFeatures());
/* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
FAILOSERR(LaunchToolServer(&psn));
/* It would be disastrous to send the event to ourselves (I know: I tried) */
FAILOSERR(GetCurrentProcess(&me));
FAILOSERR(SameProcess(&psn, &me, &same));
if (same)
return appMemFullErr; /* This is a lie. So what ? */
/* Build shell wrapper for command string */
FAILOSERR(PtrToHand(BEGIN_TEXT, &text, strlen(BEGIN_TEXT)));
FAILOSERR(Path2FSSpec(":", &vol));
segment = FSp2FullPath(&vol);
FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
FAILOSERR(PtrAndHand(DIRSET_TEXT, text, strlen(DIRSET_TEXT)));
FAILOSERR(PtrAndHand(commandline, text, strlen(commandline)));
FAILOSERR(PtrAndHand(END_TEXT, text, strlen(END_TEXT)));
DEVSTRING(input);
FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
FAILOSERR(PtrAndHand(STDOUT_TEXT, text, strlen(STDOUT_TEXT)));
DEVSTRING(output);
FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
FAILOSERR(PtrAndHand(STDERR_TEXT, text, strlen(STDERR_TEXT)));
DEVSTRING(error);
FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
FAILOSERR(PtrAndHand(TERM_TEXT, text, strlen(TERM_TEXT)));
/* Build the AppleEvent */
FAILOSERR(
AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), &addr));
FAILOSERR(
AECreateAppleEvent('misc', 'dosc', &addr,
kAutoGenerateReturnID, kAnyTransactionID,
&cmd));
HLock(text);
FAILOSERR(
AEPutParamPtr(&cmd, '----', typeChar, *text, GetHandleSize(text)));
DisposHandle(text);
/* Send it */
acur = (acurHandle) GetResource('acur', 128);
DetachResource((Handle) acur);
InitCursorCtl(acur);
err =
AESend(
&cmd, &reply, kAEWaitReply+kAENeverInteract,
kAENormalPriority, kNoTimeOut,
(IdleProcPtr) SubLaunchIdle, nil);
AEDisposeDesc(&cmd);
AEDisposeDesc(&addr);
AEDisposeDesc(&reply);
ReleaseResource((Handle) acur);
InitCursorCtl(NULL);
return err;
}